/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦]
 * 
 * https://zhiqim.org/project/zhiqim_framework/zhiqim_kernel.htm
 *
 * Zhiqim Kernel is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.zhiqim.kernel.util;

import java.math.BigDecimal;

import org.zhiqim.kernel.annotation.AnAlias;
import org.zhiqim.kernel.constants.SignConstants;

/**
 * 小数计算
 *
 * @version v8.0.1 @author zouzhigang 2021年8月31日 新建与整理
 */
@AnAlias("Decimals")
public class Decimals implements SignConstants
{
    /********************************************************************************/
    //刻度&单位
    /********************************************************************************/
    
    /** 通过小数，获取小数精度 */
    public static int scale(String unit)
    {
        Asserts.as(Validates.isFloatNonnegative(unit)?null:"参数都必须是整数或小数");
        
        return new BigDecimal(unit).scale();
    }
    
    /** 通过小数精度，获取小数值 */
    public static String unit(int scale)
    {
        if (scale <= 0)
            return "1";
        
        StringBuilder strb = new StringBuilder("0.");
        for (int i=1;i<scale;i++)
            strb.append("0");
        strb.append("1");
        return strb.toString();
    }
    
    /********************************************************************************/
    //转BigDecimal
    /********************************************************************************/
    
    /** 字符串转BigDecimal，支持空格时采用_B_0_ */
    public static BigDecimal val(String val)
    {
        return Validates.isEmptyBlank(val)?_B_0_:new BigDecimal(val);
    }
    
    /** 整型转BigDecimal */
    public static BigDecimal val(int val)
    {
        return new BigDecimal(val);
    }
    
    /** 长整型转BigDecimal */
    public static BigDecimal val(long val)
    {
        return new BigDecimal(val);
    }
    
    /** 浮点型转BigDecimal */
    public static BigDecimal val(double val)
    {
        return BigDecimal.valueOf(val).stripTrailingZeros();
    }

    /********************************************************************************/
    //转String
    /********************************************************************************/
    
    /** 去除尾部多余的零转为文本字符串 */
    public static String strip(BigDecimal val)
    {
        return val.stripTrailingZeros().toPlainString();
    }
    
    /** 去尾法保留scale位小数 */
    public static String floor(BigDecimal val, int scale)
    {
        return (val == null)?_EMPTY_:strip(val.setScale(scale, _B_F_));
    }
    
    /** 去尾法保留单位对应的小数 */
    public static String floor(BigDecimal val, String unit)
    {
        return floor(val, scale(unit));
    }
    
    /** 去尾法保留scale位小数 */
    public static String floor(String val, int scale)
    {
        return Validates.isEmptyBlank(val)?_EMPTY_:floor(val(val), scale);
    }
    
    /** 去尾法保留单位对应的小数 */
    public static String floor(String val, String unit)
    {
        return floor(val, scale(unit));
    }
    
    /** 四舍五入法保留scale位小数 */
    public static String halfup(BigDecimal val, int scale)
    {
        return (val == null)?_EMPTY_:strip(val.setScale(scale, _B_H_));
    }
    
    /** 四舍五入法保留单位对应的小数 */
    public static String halfup(BigDecimal val, String unit)
    {
        return halfup(val, scale(unit));
    }
    
    /** 四舍五入法保留scale位小数 */
    public static String halfup(String val, int scale)
    {
        return Validates.isEmptyBlank(val)?_EMPTY_:halfup(val(val), scale);
    }
    
    /** 四舍五入法保留单位对应的小数 */
    public static String halfup(String val, String unit)
    {
        return halfup(val, scale(unit));
    }
    
    /** 进一法保留scale位小数 */
    public static String ceiling(BigDecimal val, int scale)
    {
        return (val == null)?_EMPTY_:strip(val.setScale(scale, _B_C_));
    }
    
    /** 进一法保留单位对应的小数 */
    public static String ceiling(BigDecimal val, String unit)
    {
        return ceiling(val, scale(unit));
    }
    
    /** 进一法保留scale位小数 */
    public static String ceiling(String val, int scale)
    {
        return Validates.isEmptyBlank(val)?_EMPTY_:ceiling(val(val), scale);
    }
    
    /** 进一法保留单位对应的小数 */
    public static String ceiling(String val, String unit)
    {
        return ceiling(val, scale(unit));
    }

    /********************************************************************************/
    //百分比 pc & precent
    /********************************************************************************/
    
    /** 转化为百分比 */
    public static BigDecimal pc(int val)
    {
        return new BigDecimal(val).divide(_B_100_);
    }
    
    /** 转化为百分比 */
    public static BigDecimal pc(String val)
    {
        return Validates.isEmptyBlank(val)?_B_0_:new BigDecimal(val).divide(_B_100_);
    }
    
    /** 转化为百分比，即*100保留sacle小数位，四舍五入 */
    public static BigDecimal pc(String val, int sacle)
    {
        return Validates.isEmptyBlank(val)?_B_0_:new BigDecimal(val).divide(_B_100_, sacle, _B_H_);
    }
    
    /** 转化为百分比 */
    public static String precent(int val)
    {
        return strip(new BigDecimal(val).divide(_B_100_));
    }
    
    /** 转化为百分比 */
    public static String precent(String val)
    {
        return Validates.isEmptyBlank(val)?_ZERO_:strip(new BigDecimal(val).divide(_B_100_));
    }
    
    /** 转化为百分比，即*100保留sacle小数位，四舍五入 */
    public static String precent(String val, int sacle)
    {
        return Validates.isEmptyBlank(val)?_ZERO_:halfup(new BigDecimal(val).divide(_B_100_), sacle);
    }
    
    /********************************************************************************/
    //价格 px & price
    /********************************************************************************/
    
    /** 计算均价，四舍五入 */
    public static BigDecimal px(String amount, String quantity, int scale)
    {
        return d(amount, quantity, scale);
    }
    
    /** 计算均价，四舍五入 */
    public static String price(String amount, String quantity, int scale)
    {
        return ds(amount, quantity, scale);
    }

    /********************************************************************************/
    //相加
    /********************************************************************************/
    
    /** 相加 */
    public static BigDecimal a(BigDecimal val1, BigDecimal val2)
    {
        return val1.add(val2);
    }
    
    /** 相加四舍五入 */
    public static BigDecimal a(BigDecimal val1, BigDecimal val2, int scale)
    {
        return val1.add(val2).setScale(scale, _B_H_);
    }
    
    /** 相加去尾法 */
    public static BigDecimal af(BigDecimal val1, BigDecimal val2, int scale)
    {
        return val1.add(val2).setScale(scale, _B_F_);
    }
    
    /** 相加进一法 */
    public static BigDecimal ac(BigDecimal val1, BigDecimal val2, int scale)
    {
        return val1.add(val2).setScale(scale, _B_C_);
    }
    
    /** 相加 */
    public static BigDecimal a(String val1, String val2)
    {
        return val(val1).add(val(val2));
    }
    
    /** 相加得字符串 */
    public static String as(String val1, String val2)
    {
        return strip(val(val1).add(val(val2)));
    }
    
    /********************************************************************************/
    //相减
    /********************************************************************************/
    
    /** 相减 */
    public static BigDecimal s(BigDecimal val1, BigDecimal val2)
    {
        return val1.subtract(val2);
    }
    
    /** 相减四舍五入 */
    public static BigDecimal s(BigDecimal val1, BigDecimal val2, int scale)
    {
        return val1.subtract(val2).setScale(scale, _B_H_);
    }
    
    /** 相减去尾法 */
    public static BigDecimal sf(BigDecimal val1, BigDecimal val2, int scale)
    {
        return val1.subtract(val2).setScale(scale, _B_F_);
    }
    
    /** 相减进一法 */
    public static BigDecimal sc(BigDecimal val1, BigDecimal val2, int scale)
    {
        return val1.subtract(val2).setScale(scale, _B_C_);
    }
    
    /** 相减 */
    public static BigDecimal s(String val1, String val2)
    {
        return val(val1).subtract(val(val2));
    }
    
    /** 相减得字符串 */
    public static String ss(String val1, String val2)
    {
        return strip(val(val1).subtract(val(val2)));
    }
    
    /********************************************************************************/
    //相乘
    /********************************************************************************/
    
    /** 相乘 */
    public static BigDecimal m(BigDecimal val1, BigDecimal val2)
    {
        return val1.multiply(val2);
    }
    
    /** 相乘四舍五入 */
    public static BigDecimal m(BigDecimal val1, BigDecimal val2, int scale)
    {
        return val1.multiply(val2).setScale(scale, _B_H_);
    }
    
    /** 相乘去尾法 */
    public static BigDecimal mf(BigDecimal val1, BigDecimal val2, int scale)
    {
        return val1.multiply(val2).setScale(scale, _B_F_);
    }
    
    /** 相乘进一法 */
    public static BigDecimal mc(BigDecimal val1, BigDecimal val2, int scale)
    {
        return val1.multiply(val2).setScale(scale, _B_C_);
    }
    
    /** 相乘 */
    public static BigDecimal m(String val1, String val2)
    {
        return val(val1).multiply(val(val2));
    }
    
    /** 相乘 */
    public static BigDecimal m(String val1, String val2, int scale)
    {
        return val(val1).multiply(val(val2)).setScale(scale, _B_H_);
    }
    
    /** 相乘得字符串 */
    public static String ms(String val1, String val2)
    {
        return strip(val(val1).multiply(val(val2)));
    }
    
    /** 相乘得字符串 */
    public static String ms(String val1, String val2, int scale)
    {
        return strip(val(val1).multiply(val(val2)).setScale(scale, _B_H_));
    }
    
    /********************************************************************************/
    //相除
    /********************************************************************************/
    
    /** 相除 */
    public static BigDecimal d(BigDecimal val1, BigDecimal val2)
    {
        return val1.divide(val2);
    }
    
    /** 相除四舍五入 */
    public static BigDecimal d(BigDecimal val1, BigDecimal val2, int scale)
    {
        return val1.divide(val2, scale,  _B_H_);
    }
    
    /** 相除去尾法 */
    public static BigDecimal df(BigDecimal val1, BigDecimal val2, int scale)
    {
        return val1.divide(val2, scale,  _B_F_);
    }
    
    /** 相除进一法 */
    public static BigDecimal dc(BigDecimal val1, BigDecimal val2, int scale)
    {
        return val1.divide(val2, scale,  _B_C_);
    }
    
    /** 相除 */
    public static BigDecimal d(String val1, String val2)
    {
        return val(val1).divide(val(val2));
    }
    
    /** 相除四舍五入 */
    public static BigDecimal d(String val1, String val2, int scale)
    {
        return val(val1).divide(val(val2), scale, _B_H_);
    }
    
    /** 相除去尾法 */
    public static BigDecimal df(String val1, String val2, int scale)
    {
        return val(val1).divide(val(val2), scale, _B_F_);
    }
    
    /** 相除进一法 */
    public static BigDecimal dc(String val1, String val2, int scale)
    {
        return val(val1).divide(val(val2), scale, _B_C_);
    }
    
    /** 相除得字符串 */
    public static String ds(String val1, String val2)
    {
        return strip(val(val1).divide(val(val2)));
    }
    
    /** 相除四舍五入得字符串 */
    public static String ds(String val1, String val2, int scale)
    {
        return strip(val(val1).divide(val(val2), scale, _B_H_));
    }
    
    /** 相除去尾法得字符串 */
    public static String dfs(String val1, String val2, int scale)
    {
        return strip(val(val1).divide(val(val2), scale, _B_F_));
    }
    
    /** 相除进一法得字符串 */
    public static String dcs(String val1, String val2, int scale)
    {
        return strip(val(val1).divide(val(val2), scale, _B_C_));
    }
}
